export interface IResColor {
  cmyk: number[];
  hex: string;
  rgb: number[];
}

/**配置参数 */
export interface IColorOptions {
  /**canvas元素选择器 */
  el: string;
  /**取色回调函数 */
  onChange: (value: IResColor) => void;
}


/**样式对象 */
const styles = {
  canvasParent: {
    width: '100%',
    height: '100%',
    position: 'fixed'
  },
  canvas: {
    width: '100%',
    height: '100%',
  },
  glass: {
    position: "fixed",
    overflow: "hidden",
    left: 0,
    top: 0,
    width: '153px',
    height: '153px',
    borderRadius: '50%',
    boxSizing: 'border-box',
    border: '1px solid #33333366',
    display: 'none',
    pointerEvents: 'none'
  },
  colorBox: {
    boxSizing: 'border-box',
    position: 'absolute',
    bottom: '10px',
    left: 'calc(50% - 38px)',
    width: '76px',
    height: '28px',
    textAlign: 'center',
    backgroundColor: '#000000cc',
    color: '#ffffff',
    padding: '6px 5px',
    fontSize: '12px',
    borderRadius: '4px'
  },
  glassCanvas: {
    border: '1px solid #33333366',
    borderRadius: '50%',
    margin: '3px',
    cursor: 'none',
    display: 'inline-block'
  }
}

export default class ColorPicker {
  /**取色容器 */
  private container: HTMLElement | undefined;
  /**取色用的canvas */
  private colorPickerCanvas: HTMLCanvasElement;
  /**取色器canvas对象 */
  private colorPickerCanvasCtx: CanvasRenderingContext2D | undefined;
  /**放大镜 */
  private glass: HTMLElement | undefined;
  /**放大镜展示颜色用的canvas */
  private glassCtx: CanvasRenderingContext2D | undefined;
  /**颜色数量 */
  colorCount: number = 6;
  /**取色器各个数 */
  private gridCount: number = 11;
  /**取色器格子宽度 */
  private gridWidth: number = 13;
  /**当前中心的颜色值 */
  private curColor: string = "";
  /**当前选择的RGB颜色 */
  private curRgbColor: number[] | undefined;
  /**色值展示容器 */
  private colorShowBox: HTMLElement | undefined;

  /**点击回调函数 返回颜色值 */
  private onChange: (color: IResColor) => void;
  constructor(options: IColorOptions) {
    this.onChange = options.onChange;
    const canvas = document.querySelector(options.el) as HTMLCanvasElement;
    console.log(canvas);

    this.colorPickerCanvas = canvas;
  }

  /**颜色转换（RGB转CMYK） */
  public RGBToCMYK([R, G, B]: number[]): number[] {
    let r = R / 255;
    let g = G / 255;
    let b = B / 255
    let K = Math.round((1 - Math.max(r, g, b)) * 10000) / 10000
    let C = Math.round(((1 - r - K) / (1 - K)) * 10000) / 10000
    let M = Math.round(((1 - g - K) / (1 - K)) * 10000) / 10000
    let Y = Math.round((1 - b - K) / (1 - K) * 10000) / 10000
    return [C, M, Y, K];
  }

  /**颜色转换（RGB转HEX） */
  public RGBToHex([R, G, B]: number[]): string {
    let r: string = Math.trunc(R / 16).toString(16) + (R % 16).toString(16)
    let g: string = Math.trunc(G / 16).toString(16) + (G % 16).toString(16)
    let b: string = Math.trunc(B / 16).toString(16) + (B % 16).toString(16)
    return '#' + r + g + b;
  }

  /**颜色装换（HEX转RGB） */
  public HexToRGB(hex: string): number[] {
    let rgba = [];
    hex = hex.replace('#', '').padEnd(8, 'F');
    for (let i = 0; i < hex.length; i += 2) {
      rgba.push(parseInt(hex.slice(i, i + 2), 16))
    }
    return rgba
  }

  /**颜色转换（Hex转CMYK） */
  public HexToCMYK(hex: string): number[] {
    let rgb = this.HexToRGB(hex)
    let cmyk = this.RGBToCMYK(rgb)
    return cmyk;
  }

  /**颜色装换（CMYK转RGB） */
  public CMYKtoRGB([c, m, y, k]: number[]): number[] {
    let r, g, b;
    r = Math.round((1 - c) * (1 - k) * 255);
    g = Math.round((1 - m) * (1 - k) * 255);
    b = Math.round((1 - y) * (1 - k) * 255);
    return [r, g, b]
  }

  /**打开取色器 */
  public open() {
    this.container = this.colorPickerCanvas.parentElement as HTMLElement;
    this.colorPickerCanvasCtx = this.colorPickerCanvas.getContext('2d', { willReadFrequently: true }) as CanvasRenderingContext2D
    if (this.container) {
      this.glass = this.magnifyingGlass()
      // 添加事件
      this.colorPickerCanvas.addEventListener('mousemove', this.onCanvasMove, false)
      this.colorPickerCanvas.addEventListener('mouseleave', this.onCanvasOut, false)
      this.colorPickerCanvas.addEventListener('mousedown', this.onCanvasClick, false)
      this.glass.addEventListener('mousemove', this.onCanvasMove, false)
      window.addEventListener('keydown', this.onKeyDown, false)
      this.colorPickerCanvas.style.cursor = 'none'
    }
  }

  /**创建取色放大镜 */
  private magnifyingGlass(): HTMLElement {
    let glass = this.createHTMLTag('div', this.container as HTMLElement, styles.glass)
    glass.id = 'glass'
    this.colorShowBox = this.createHTMLTag('div', glass, styles.colorBox);
    // 放大镜画布
    let glassCanvas = this.createHTMLTag('canvas', glass, styles.glassCanvas)
    glassCanvas.height = 143;
    glassCanvas.width = 143;
    this.glassCtx = glassCanvas.getContext('2d') as CanvasRenderingContext2D;
    this.drawGrid()
    return glass;
  }

  /**绘制网格线 */
  drawGrid() {
    if (!this.glassCtx) {
      return
    }
    this.glassCtx.strokeStyle = '#999999'
    this.glassCtx.lineWidth = 1;
    // 绘制竖线
    for (let i = 0; i < this.gridCount; i++) {
      let x = i % this.gridCount * this.gridWidth
      this.glassCtx.moveTo(x + 0.5, 0)
      this.glassCtx.lineTo(x + 0.5, 143)
    }
    // 绘制横线
    for (let i = 0; i < this.gridCount; i++) {
      let y = i % this.gridCount * this.gridWidth;
      this.glassCtx.moveTo(0, y + 0.5)
      this.glassCtx.lineTo(143, y + 0.5)
    }
    this.glassCtx.stroke()
  }

  /**绘制颜色网格 */
  private grawColorGrid(fillColor: number[][]) {
    if (!this.glassCtx) {
      return
    }
    let centerX: number = 0, centerY: number = 0;
    for (let i = 0; i < this.gridCount * this.gridCount; i++) {
      let x = i % this.gridCount * this.gridWidth;
      let y = Math.trunc(i / this.gridCount) * this.gridWidth;
      let row = Math.ceil(i / this.gridCount)
      let col = i - (row - 1) * this.gridCount;
      this.glassCtx.lineWidth = 1;
      if (row == 6 && col == 5) {
        // 中心点颜色填充
        this.curRgbColor = fillColor[i];
        this.curColor = this.RGBToHex(fillColor[i])
        this.glassCtx.fillStyle = this.curColor
        if (this.colorShowBox) {
          this.colorShowBox.innerText = this.curColor;
        }
        this.glassCtx.fillRect(x, y, this.gridWidth, this.gridWidth)
        centerX = x
        centerY = y
        this.glassCtx.stroke()
      } else {
        // this.glassCtx.fillStyle = `rgba(${fillColor[i].join(',')}`
        this.glassCtx.fillStyle = this.RGBToHex(fillColor[i])
        this.glassCtx.fillRect(x, y, this.gridWidth, this.gridWidth)
        this.glassCtx.stroke()
      }
    }
    // 中心点矩形
    this.glassCtx.lineWidth = 3;
    this.glassCtx.strokeStyle = '#ffffff'
    this.glassCtx.strokeRect(centerX + 0.5, centerY + 0.5, this.gridWidth, this.gridWidth)
    // 恢复画布颜色线条属性
    this.glassCtx.lineWidth = 1;
    this.glassCtx.strokeStyle = '#999999'
    this.glassCtx.stroke()
  }

  /**获取放大镜区域颜色 */
  private getColors(x: number, y: number) {
    if (this.colorPickerCanvasCtx) {
      const { data } = this.colorPickerCanvasCtx.getImageData(x - 5, y - 5, this.gridCount, this.gridCount);
      // 遍历色块，组成rgb颜色
      let colors: number[][] = [];
      for (let i = 0; i < data.length; i += 4) {
        colors.push([data[i], data[i + 1], data[i + 2], data[i + 3]])
      }
      this.grawColorGrid(colors)
    }
  }

  /**鼠标hover监听事件 */
  private onCanvasMove = (e: MouseEvent) => {
    if (!this.glass) {
      return
    }
    this.glass.style.display = 'block';
    if (this.glassCtx) {
      let x = e.offsetX * window.devicePixelRatio;
      let y = e.offsetY * window.devicePixelRatio;
      // transform会导致canvas绘制线条模糊
      // this.glass.style.transform = `translate(${e.pageX - 76.5}px, ${e.pageY - 76.5}px)`;
      this.glass.style.left = `${e.pageX - 76.5}px`;
      this.glass.style.top = `${e.pageY - 76.5}px`;
      this.getColors(x, y)
    }
  }

  /**鼠标移出画布--取色器影藏 */
  private onCanvasOut = () => {
    if (this.glass) {
      this.glass.style.display = 'none'
    }
  }

  /**鼠标点击事件监听--获取色值 */
  private onCanvasClick = () => {
    this.onChange({
      cmyk: this.RGBToCMYK(this.curRgbColor ?? []),
      hex: this.curColor,
      rgb: this.curRgbColor ?? [],
    });
  }

  /**监听键盘事件--销毁监听及取色器 */
  private onKeyDown = (e: KeyboardEvent) => {
    if (e.code === 'Escape') {
      this.destroy();
    }
  }

  /**销毁方法 */
  public destroy() {
    this.colorPickerCanvas?.removeEventListener('mousemove', this.onCanvasMove, false)
    this.colorPickerCanvas?.removeEventListener('mouseleave', this.onCanvasOut, false)
    this.glass?.removeEventListener('mousedown', this.onCanvasClick, false)
    this.glass?.removeEventListener('mousemove', this.onCanvasMove, false)
    if (this.colorPickerCanvas) {
      this.colorPickerCanvas.style.cursor = 'auto'
    }
    if (this.container) {
      if (this.glass) this.container.removeChild(this.glass)
      if (this.container) document.body.removeChild(this.container)
    }
    this.container = undefined;
    this.glass = undefined;
    this.colorPickerCanvasCtx = undefined;
    window.removeEventListener('keydown', this.onKeyDown, false);
  }

  /**创建元素方法 */
  private createHTMLTag<T extends keyof HTMLElementTagNameMap>(tagName: T, parentTag: HTMLElement | DocumentFragment, style?: Record<string, string | number>): HTMLElementTagNameMap[T] {
    const el = document.createElement(tagName);
    for (const key in style) {
      if (Object.prototype.hasOwnProperty.call(style, key)) {
        const value = style[key];
        Reflect.set(el.style, key, value)
      }
    }
    parentTag.appendChild(el);
    return el;
  }
}

